Skip to main content

Overview

Fetches the latest daily price band changes (circuit limit revisions) from NSE Archives. The script checks the last 7 days backwards from today to find the most recent CSV file, as NSE does not publish these files on weekends or holidays. Source: fetch_incremental_price_bands.py
Phase: Phase 2 (Enrichment)
Output: incremental_price_bands.json

Data Source

NSE Archives CSV Endpoint

GET https://nsearchives.nseindia.com/content/equities/eq_band_changes_{date}.csv
date
string
required
Date in ddmmyyyy format (e.g., 03032024 for March 3, 2024)

Example URL

https://nsearchives.nseindia.com/content/equities/eq_band_changes_03032024.csv

CSV Format

The NSE CSV contains the following structure (example):
Symbol,Series,Date,New Band,Old Band,Applicable Date
RELIANCE,EQ,03-MAR-2024,10,20,04-MAR-2024
TATASTEEL,EQ,03-MAR-2024,20,10,04-MAR-2024

Function Signature

def fetch_nse_price_bands():
    """
    Fetches the latest price band changes CSV from NSE Archives.
    Searches backwards up to 7 days to find the most recent file.
    Parses CSV using pandas and saves as JSON.
    """

Date Search Logic

Searches backwards from today up to 7 days:
today = datetime.now()
clean_data = []

for i in range(8):  # 0-7 days back
    check_date = today - timedelta(days=i)
    date_str = check_date.strftime("%d%m%Y")  # Format: ddmmyyyy 
    url = base_url.format(date=date_str)
    
    response = requests.get(url, headers=headers, timeout=10)
    if response.status_code == 200:
        # Found the file, parse and break
        break

CSV Parsing

Uses pandas for robust CSV parsing:
csv_content = response.content.decode('utf-8')
df = pd.read_csv(io.StringIO(csv_content))

# Convert to list of dictionaries
raw_data = df.to_dict(orient='records')

# Clean whitespace from keys and values
for record in raw_data:
    cleaned_record = {}
    for k, v in record.items():
        key = k.strip() if isinstance(k, str) else k
        value = v.strip() if isinstance(v, str) else v
        cleaned_record[key] = value
    clean_data.append(cleaned_record)

Output Structure

Symbol
string
Stock trading symbol
Series
string
Series type (typically “EQ” for equity)
Date
string
Date of band change announcement
New Band
string
New circuit limit percentage
Old Band
string
Previous circuit limit percentage
Applicable Date
string
Date when new band becomes effective

Example Output

[
  {
    "Symbol": "RELIANCE",
    "Series": "EQ",
    "Date": "03-MAR-2024",
    "New Band": "10",
    "Old Band": "20",
    "Applicable Date": "04-MAR-2024"
  },
  {
    "Symbol": "TATASTEEL",
    "Series": "EQ",
    "Date": "03-MAR-2024",
    "New Band": "20",
    "Old Band": "10",
    "Applicable Date": "04-MAR-2024"
  }
]

Dependencies

  • requests — HTTP client for downloading CSV
  • json — JSON serialization
  • datetime — Date calculations
  • pandas — CSV parsing and data manipulation
  • io — In-memory file handling for CSV parsing

HTTP Headers

headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
    "Accept": "*/*"
}

Error Handling

  • 10-second timeout per HTTP request
  • Gracefully handles 404 (file not found) for non-trading days
  • Continues searching backwards through date range
  • Reports parse errors but continues to next date
if response.status_code == 200:
    print(f"  Found data for {date_str}!")
    # Parse and break
elif response.status_code == 404:
    print(f"  No file found for {date_str} (404).")
else:
    print(f"  Unexpected status {response.status_code} for {date_str}.")

Usage Example

python3 fetch_incremental_price_bands.py
Expected Output:
Checking for price band changes on 03032024...
  Found data for 03032024!
Successfully saved 15 price band changes to incremental_price_bands.json
On Weekend/Holiday:
Checking for price band changes on 03032024...
  No file found for 03032024 (404).
Checking for price band changes on 02032024...
  No file found for 02032024 (404).
Checking for price band changes on 01032024...
  Found data for 01032024!
Successfully saved 12 price band changes to incremental_price_bands.json

Integration

This script is part of Phase 2 (Enrichment) in the EDL Pipeline. The output file is consumed by:
  • add_corporate_events.py — Adds ”#: +/- Revision” event markers for price band changes
  • bulk_market_analyzer.py — Updates the “Circuit Limit” field
Run via master pipeline:
python3 run_full_pipeline.py

Data Availability Notes

  • NSE typically publishes this file on trading days only
  • File is usually available after market close (3:30 PM IST)
  • Weekends and holidays will have no file (404 response)
  • The 7-day search window ensures catching the latest file even after long weekends

Field Interpretation

Band Meanings:
  • 2% — Very high surveillance/volatility
  • 5% — High surveillance
  • 10% — Moderate surveillance
  • 20% — Normal (standard circuit limit)
Lower band values indicate tighter restrictions and higher regulatory scrutiny.